package org.testis.gui.mvc.controller.testdesign;

import org.testis.data.parser.DynamicMapTreeProviderFactory;
import org.testis.gui.mvc.controller.*;
import org.testis.gui.mvc.model.testdesign.RunningTestSuiteModel;
import org.testis.gui.mvc.utilities.GUIMessageListener;
import org.testis.gui.mvc.utilities.TestRunner;
import org.testis.gui.mvc.utilities.ValidationUtils;
import org.testis.gui.mvc.view.testdesign.RunningTestSuiteView;
import org.testis.testdriver.AtofEnumaration.ExecutionInterventionType;
import org.testis.threading.TaskExecutor;
import org.testis.utils.tree.MyDefaultMutableTreeNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

import org.testis.orm.refinedclasses.TestDesignTreeNode;

/**
 *
 * @author Cahit Emir Erel
 */
public class RunningTestSuiteController extends AbstractController {

    public static final String SHOW_RUN_TEST_SUITE = "RunTestSuiteVisibility";
    public static final String CHANGE_MODE = "Mode";
    public static final String CHANGE_STATE = "RunningState";
    public static final String IS_RUNNING = "Running";
    public static final String CHANGE_OUTPUT = "Output";
    public static final String TEST_END = "TestEnd";
    public static final String ENABLE_ABORT_BUTTON = "AbortEnability";
    public static final String ENABLE_RETRY_BUTTON = "RetryEnability";
    public static final String ENABLE_CONTINUE_BUTTON = "ContinueEnability";
    private LinkedList<MyDefaultMutableTreeNode> m_selectedNodes;
    private TaskExecutor executor;
    private List<TestRunner> runners;

    public RunningTestSuiteController() {
        super();
    }

    public void operationRunTestSuite(
            LinkedList<MyDefaultMutableTreeNode> selectedNodes) {
        if (selectedNodes.size() == 0) {
            TestDesignControllerList.newInstance().getTreeController().
                    operationGenerateErrorMessage(
                    "The Test Suite you want to run is NOT selected",
                    "ERROR");
            return;
        }
        initialize();
        m_selectedNodes = selectedNodes;
        operationChangeMode("Runner");
        setModelProperty(SHOW_RUN_TEST_SUITE,
                true);
    }

    public void operationSetRunning(Boolean isRunning) {

        setModelProperty(IS_RUNNING,
                isRunning);
    }

    public void operationDebuggingBreak(Boolean isBreak) {
        setModelProperty(ENABLE_RETRY_BUTTON,
                isBreak);
        setModelProperty(ENABLE_ABORT_BUTTON,
                isBreak);
        setModelProperty(ENABLE_CONTINUE_BUTTON,
                isBreak);
    }

    public void operationStart(GUIMessageListener call) {
        int count = m_selectedNodes.size();
        StringBuilder sb = new StringBuilder();
        sb.append("You are about to running multiple test suites. Count="
                + count + "\n");
        for (int i = 0; i < m_selectedNodes.size(); i++) {
            TestDesignTreeNode testSuite =
                    (TestDesignTreeNode) m_selectedNodes.get(i).getUserObject();
            sb.append((i + 1) + "." + testSuite.getName() + "\n");

        }
        if (count > 1) {
            sb.append("Confirm if you want to continue");
            boolean result =
                    TestDesignControllerList.newInstance().getTreeController().
                    operationShowConfirmDialogBox(sb.toString(),
                    "Warning-Running multiple test suites");
            if (!result) {
                operationStop();
                return;
            }
        }
        DynamicMapTreeProviderFactory.getInstance().clearDynamicMapTrees();
        System.out.println("EXECUTING NO OF TREES:" + m_selectedNodes.size());
        HashMap<MyDefaultMutableTreeNode, Integer> runCounts = new HashMap<MyDefaultMutableTreeNode, Integer>();
        int maxQueeSize = m_selectedNodes.size();
        for (int i = 0; i < m_selectedNodes.size(); i++) {
            TestDesignTreeNode testSuite =
                    (TestDesignTreeNode) m_selectedNodes.get(i).getUserObject();
            String result = javax.swing.JOptionPane.showInputDialog(testSuite.getName() + "-> Run Count", "1");
            if(result==null)
            {
                operationStop();
                return;
            }
            if (result.equals("") && !ValidationUtils.isNumeric(result.trim())) {
                result = "1";
            } else {
                result = result.trim();
            }
            runCounts.put(m_selectedNodes.get(i), Integer.parseInt(result));
            maxQueeSize = maxQueeSize + Integer.parseInt(result) - 1;
        }
        runners = new ArrayList<TestRunner>();
        executor =
                new TaskExecutor(0,
                1,
                maxQueeSize, Long.MAX_VALUE);
        for (int i = 0; i < m_selectedNodes.size(); i++) {
            TestDesignTreeNode testTree = TestDesignControllerList.newInstance().
                    getTreeController().constructRunTree(m_selectedNodes.get(
                    i),
                    null);
            int runCount = runCounts.get(m_selectedNodes.get(i));
            for (int j = 0; j < runCount; j++) {

                int modeEnum = -1;
                String mode = (String) getModelProperty(CHANGE_MODE);
                if (mode.equals("Runner")) {
                    modeEnum = 2;
                } else if (mode.equals("Debugger")) {
                    modeEnum = 1;
                } else if (mode.equals("Failed Debugger")) {
                    modeEnum = 0;
                }
                TestRunner tmp = new TestRunner(testTree,
                        modeEnum, UUID.randomUUID().toString());
                runners.add(tmp);
                executor.execute(tmp);
            }
        }
    }

    public void operationStop() {

        operationSetRunning(false);
        setModelProperty(TEST_END, true);
    }

    public boolean operationAbort() {
        if (executor.getLastRunnable() != null) {
            for (int i = 0; i < runners.size(); i++) {
                executor.remove(runners.get(i));
            }
            ((TestRunner) executor.getLastRunnable()).setExecutionIntervention(ExecutionInterventionType.Abort);
            return true;
        }
        return false;
    }

    public boolean operationPause() {
        if (executor.getLastRunnable() != null) {
            ((TestRunner) executor.getLastRunnable()).setExecutionIntervention(ExecutionInterventionType.Pause);
            return true;
        }
        return false;
    }

    public boolean operationResume() {
        if (executor.getLastRunnable() != null) {
            ((TestRunner) executor.getLastRunnable()).setExecutionIntervention(ExecutionInterventionType.Resume);
            return true;
        }
        return false;
    }

    public void initialize() {
        RunningTestSuiteModel runningTestSuiteModel =
                new RunningTestSuiteModel();
        RunningTestSuiteView runningTestSuiteView =
                new RunningTestSuiteView(TestDesignControllerList.newInstance().
                getParentFrame(),
                true);
        addModel(runningTestSuiteModel);
        addView(runningTestSuiteView);
        runningTestSuiteView.pack();
    }

    public void operationChangeMode(String name) {
        setModelProperty(CHANGE_MODE,
                name);
    }

    public void operationChangeOutput(String output) {
        setModelProperty(CHANGE_OUTPUT,
                output);
    }

    public void operationCloseWindow() {
        cleanAll();
    }

    public void operationStateChanged(ExecutionInterventionType executionInterventionType) {
        setModelProperty(CHANGE_STATE, executionInterventionType);

    }

    public void setExecutionIntervention(ExecutionInterventionType val) {
        if (executor.getLastRunnable() != null) {
            ((TestRunner) executor.getLastRunnable()).setExecutionIntervention(val);
        }
    }
}
